/*
 * chat_client.cpp
 * 
 * Chat Server 测试客户端
 * 用于测试聊天服务器的各项功能
 */

#include "protocol/PacketHeader.h"
#include "protocol/MessageCodec.h"
#include "chat.pb.h"

#include <muduo/net/TcpClient.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/base/Logging.h>

#include <iostream>
#include <string>
#include <thread>
#include <atomic>

using namespace muduo;
using namespace muduo::net;

class ChatClient {
public:
    ChatClient(EventLoop* loop, const InetAddress& serverAddr, const std::string& username)
        : loop_(loop),
          client_(loop, serverAddr, "ChatClient"),
          username_(username),
          loggedIn_(false) {
        
        client_.setConnectionCallback(
            std::bind(&ChatClient::onConnection, this, std::placeholders::_1));
        client_.setMessageCallback(
            std::bind(&ChatClient::onMessage, this, 
                     std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    }
    
    void connect() {
        client_.connect();
    }
    
    void disconnect() {
        client_.disconnect();
    }
    
    void sendChat(const std::string& content) {
        if (!loggedIn_) {
            std::cout << "Not logged in yet!" << std::endl;
            return;
        }
        
        protocol::ChatMessage msg;
        msg.set_content(content);
        
        sendMessage(protocol::MSG_CHAT, msg);
    }
    
    void sendPrivate(const std::string& to, const std::string& content) {
        if (!loggedIn_) {
            std::cout << "Not logged in yet!" << std::endl;
            return;
        }
        
        protocol::PrivateMessage msg;
        msg.set_to(to);
        msg.set_content(content);
        
        sendMessage(protocol::MSG_PRIVATE, msg);
    }
    
    void requestUserList() {
        if (!loggedIn_) {
            std::cout << "Not logged in yet!" << std::endl;
            return;
        }
        
        protocol::UserListRequest msg;
        sendMessage(protocol::MSG_USER_LIST, msg);
    }

private:
    void onConnection(const TcpConnectionPtr& conn) {
        if (conn->connected()) {
            LOG_INFO << "Connected to server: " << conn->peerAddress().toIpPort();
            
            // 发送登录请求
            protocol::LoginRequest loginReq;
            loginReq.set_username(username_);
            sendMessage(protocol::MSG_LOGIN, loginReq);
        } else {
            LOG_INFO << "Disconnected from server";
            loggedIn_ = false;
        }
    }
    
    void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) {
        while (true) {
            uint16_t msgId;
            std::string data;
            int ret = protocol::MessageCodec::decode(buf, msgId, data);
            
            if (ret < 0) {
                LOG_ERROR << "Decode error, close connection";
                conn->shutdown();
                return;
            }
            
            if (ret == 0) {
                // 包不完整，等待更多数据
                return;
            }
            
            // 处理消息
            handleMessage(msgId, data, time);
        }
    }
    
    void handleMessage(uint16_t msgId, const std::string& data, Timestamp time) {
        switch (msgId) {
            case protocol::MSG_LOGIN_RESPONSE: {
                protocol::LoginResponse resp;
                if (resp.ParseFromString(data)) {
                    if (resp.result() == 0) {
                        loggedIn_ = true;
                        std::cout << "\n[System] " << resp.message() << std::endl;
                        std::cout << "[System] You are logged in as: " << username_ << std::endl;
                        printPrompt();
                    } else {
                        std::cout << "\n[System] Login failed: " << resp.message() << std::endl;
                        printPrompt();
                    }
                }
                break;
            }
            
            case protocol::MSG_CHAT: {
                protocol::ChatMessage msg;
                if (msg.ParseFromString(data)) {
                    std::cout << "\n[" << msg.from() << "] " << msg.content() << std::endl;
                    printPrompt();
                }
                break;
            }
            
            case protocol::MSG_USER_LIST_RESPONSE: {
                protocol::UserListResponse resp;
                if (resp.ParseFromString(data)) {
                    std::cout << "\n===== Online Users (" << resp.users_size() << ") =====" << std::endl;
                    for (int i = 0; i < resp.users_size(); ++i) {
                        std::cout << "  " << (i + 1) << ". " << resp.users(i) << std::endl;
                    }
                    std::cout << "============================" << std::endl;
                    printPrompt();
                }
                break;
            }
            
            case protocol::MSG_USER_JOINED: {
                protocol::UserJoinedNotify notify;
                if (notify.ParseFromString(data)) {
                    std::cout << "\n[System] User '" << notify.username() << "' joined" << std::endl;
                    printPrompt();
                }
                break;
            }
            
            case protocol::MSG_USER_LEFT: {
                protocol::UserLeftNotify notify;
                if (notify.ParseFromString(data)) {
                    std::cout << "\n[System] User '" << notify.username() << "' left" << std::endl;
                    printPrompt();
                }
                break;
            }
            
            default:
                LOG_WARN << "Unknown message ID: " << msgId;
                break;
        }
    }
    
    void sendMessage(uint16_t msgId, const google::protobuf::Message& msg) {
        TcpConnectionPtr conn = client_.connection();
        if (conn && conn->connected()) {
            Buffer buf;
            protocol::MessageCodec::encode(msgId, msg, &buf);
            conn->send(&buf);
        }
    }
    
    void printPrompt() {
        std::cout << username_ << "> " << std::flush;
    }

private:
    EventLoop* loop_;
    TcpClient client_;
    std::string username_;
    std::atomic<bool> loggedIn_;
};

void printHelp() {
    std::cout << "\n===== Chat Client Commands =====" << std::endl;
    std::cout << "  /help          - Show this help" << std::endl;
    std::cout << "  /users         - List online users" << std::endl;
    std::cout << "  /private <user> <msg> - Send private message" << std::endl;
    std::cout << "  /quit          - Quit" << std::endl;
    std::cout << "  <message>      - Send public message" << std::endl;
    std::cout << "=================================" << std::endl;
}

int main(int argc, char* argv[]) {
    Logger::setLogLevel(Logger::WARN);
    
    if (argc < 3) {
        std::cout << "Usage: " << argv[0] << " <server_ip> <username>" << std::endl;
        std::cout << "Example: " << argv[0] << " 127.0.0.1 Alice" << std::endl;
        return 1;
    }
    
    std::string serverIp = argv[1];
    std::string username = argv[2];
    uint16_t port = 8081;
    
    if (argc > 3) {
        port = static_cast<uint16_t>(std::atoi(argv[3]));
    }
    
    // EventLoop 在主线程创建
    EventLoop loop;
    InetAddress serverAddr(serverIp, port);
    ChatClient client(&loop, serverAddr, username);
    
    // 连接到服务器（在主线程，EventLoop运行前）
    client.connect();
    
    // 等待连接建立
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    
    // 打印欢迎信息
    std::cout << "====================================" << std::endl;
    std::cout << "  Chat Client - Connected to " << serverIp << ":" << port << std::endl;
    std::cout << "  Username: " << username << std::endl;
    std::cout << "====================================" << std::endl;
    printHelp();
    std::cout << std::endl;
    
    // 在子线程处理用户输入
    std::thread inputThread([&loop, &client]() {
        std::string line;
        while (std::getline(std::cin, line)) {
            if (line.empty()) {
                continue;
            }
            
            if (line[0] == '/') {
                // 处理命令
                if (line == "/quit") {
                    // 通过 runInLoop 在 EventLoop 线程中执行
                    loop.runInLoop([&client]() {
                        client.disconnect();
                    });
                    loop.runInLoop([&loop]() {
                        loop.quit();
                    });
                    break;
                } else if (line == "/help") {
                    printHelp();
                } else if (line == "/users") {
                    client.requestUserList();
                } else if (line.substr(0, 9) == "/private ") {
                    size_t pos = line.find(' ', 9);
                    if (pos != std::string::npos) {
                        std::string toUser = line.substr(9, pos - 9);
                        std::string content = line.substr(pos + 1);
                        client.sendPrivate(toUser, content);
                        std::cout << "[Private to " << toUser << "] " << content << std::endl;
                    } else {
                        std::cout << "Usage: /private <user> <message>" << std::endl;
                    }
                } else {
                    std::cout << "Unknown command. Type /help for help." << std::endl;
                }
            } else {
                // 发送聊天消息（TcpConnection::send内部是线程安全的）
                client.sendChat(line);
            }
        }
    });
    
    // 主线程运行 EventLoop（阻塞）
    loop.loop();
    
    // EventLoop 退出后，等待输入线程结束
    if (inputThread.joinable()) {
        inputThread.join();
    }
    
    std::cout << "Goodbye!" << std::endl;
    return 0;
}

